using System;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
using AnimatorController = UnityEditor.Animations.AnimatorController;

namespace UFrame
{
    /// <summary>
    /// 粒子, animator 一个类的封装, 获得他们的时间长度
    /// </summary>
    public interface ITimeObjectBase
    {
        float GetStartTime();
        float GetEndTime();
        void TimeChange(float time);
        void ChangeStartTime(float time);
        void LeaveTime(float time);
        void TimeHaveChange();

        void Add(ITimeObjectBase obj);

        void Remove(ITimeObjectBase obj);

        void SetFather(ITimeObjectBase obj);

        void Release();
    }

    public interface ITimeLineObjectBase : ITimeObjectBase
    {
        float GetTimeLength();
        string GetName();
    }

    public abstract class TimeLineObjectBase<T> : ITimeLineObjectBase
    {
        private Action<float> action;

        private float timeLength;

        private float startTime = 0;

        private ITimeObjectBase manager = null;

        protected T obj;

        public float TimeLength
        {
            set
            {
                timeLength = value;
                TimeHaveChange();
            }
            get { return timeLength; }
        }

        public float StartTime
        {
            set { ChangeStartTime(value); }
            get { return startTime; }
        }

        public Action<float> ChangeTimeAction
        {
            set { action = value; }
        }

        public virtual void SetObject(T t, Action<float> action)
        {
            obj = t;
            action = action;
        }


        public abstract void TimeChange(float time);


        public virtual void ChangeStartTime(float time)
        {
            startTime = time;
            TimeHaveChange();
            if (action != null)
            {
                action(time);
            }
        }

        public virtual void OnShow(float time)
        {
        }

        public virtual void OnHide(float time)
        {
        }

        public virtual void LeaveTime(float time)
        {
        }

        public float GetEndTime()
        {
            return startTime + timeLength;
        }

        public float GetStartTime()
        {
            return startTime;
        }

        public float GetTimeLength()
        {
            return timeLength;
        }

        public abstract string GetName();

        public void TimeHaveChange()
        {
            if (manager != null)
            {
                manager.TimeHaveChange();
            }
        }

        public void Add(ITimeObjectBase obj)
        {
        }

        public void Remove(ITimeObjectBase obj)
        {
        }

        public void SetFather(ITimeObjectBase obj)
        {
            manager = obj;
        }

        public void Release()
        {
            manager = null;
        }
    }

    public class ParticleSystemTimeControl : TimeLineObjectBase<ParticleSystem>
    {
        float curTime = 0f;

        public override void SetObject(ParticleSystem t, Action<float> action)
        {
            base.SetObject(t, action);

            if (obj.enableEmission)
            {
                if (obj.emissionRate <= 0)
                {
                    TimeLength = obj.startDelay + obj.startLifetime + 1;
                }
                else
                {
                    TimeLength = obj.startDelay + Mathf.Max(obj.duration, obj.startLifetime) + 1;
                }
            }
        }

        public override string GetName()
        {
            return obj.name;
        }

        public override void TimeChange(float time)
        {
            float curTime = time - StartTime;

            if (curTime >= 0)
            {
                if (!obj.gameObject.activeSelf)
                {
                    obj.gameObject.SetActive(true);
                    obj.time = 0f;
                    obj.Play();
                }

                float offer = curTime - curTime;

                obj.Simulate(offer, false, false);
                this.curTime = curTime;
            }
        }

        public override void OnShow(float time)
        {
            if (obj.gameObject.activeSelf)
            {
                float curTime = time - StartTime;
                obj.Simulate(0, false, true);
                obj.time = 0f;
                obj.Play();

                if (obj.startDelay > 0f)
                {
                    obj.Simulate(0.1f, false, true);
                }
                else
                {
                    obj.Simulate(curTime, false, true);
                }
            }
        }

        public override void LeaveTime(float time)
        {
            if (obj.gameObject.activeSelf)
            {
                if (this.curTime > 0f)
                {
                    obj.Simulate(-curTime, false, true);
                }

                obj.Stop();
                obj.time = 0;
                this.curTime = 0f;
            }
        }


    }

    public class AnimatorTimeControl : TimeLineObjectBase<UnityEngine.Animator>
    {
        bool isNeedRecord = true;

        public override void SetObject(Animator t, Action<float> action)
        {
            base.SetObject(t, action);
            if (obj.runtimeAnimatorController == null)
            {
                if (EditorUtility.DisplayDialog("", string.Format("对象{0}的animator是空的,无法显示", obj.name), "确定"))
                {
                    return;
                }
            }

            RuntimeAnimatorController control = t.runtimeAnimatorController;

            AnimatorController animatorcontroller =
                obj.runtimeAnimatorController as AnimatorController;
            AnimatorStateMachine sm = animatorcontroller.layers[0].stateMachine;

            string name = sm.states[0].state.name;
            if (control != null)
            {
                if (control.animationClips.Length == 1)
                {
                    AnimationClip clip = control.animationClips[0];
                    Record(clip, name);
                }
            }
        }

        public void Record(AnimationClip clip, string name)
        {
            obj.StopPlayback();
            float frameTime = 1.0f / 30;
            int frame = (int)(clip.length * clip.frameRate);
            obj.StartRecording(frame);
            obj.recorderStartTime = 0f;
            obj.Play(name);

            for (var j = 0; j <= frame; j++)
            {
                obj.Update(frameTime);
            }


            obj.StopRecording();
            obj.StartPlayback();
            TimeLength = obj.recorderStopTime;
        }

        public override string GetName()
        {
            return "";
        }

        public override void LeaveTime(float time)
        {
            if (obj.gameObject.activeSelf)
            {
                obj.playbackTime = 0;
                obj.Update(0);
                obj.StopPlayback();
                if (obj.transform.childCount == 0)
                {
                    obj.gameObject.SetActive(false);
                }
                //m_object.enabled = false;
            }
        }

        public override void TimeChange(float time)
        {
            var animatorcontroller = obj.runtimeAnimatorController as AnimatorController;

            if (!obj.gameObject.activeSelf)
            {
                obj.gameObject.SetActive(true);
                RuntimeAnimatorController control = obj.runtimeAnimatorController;
                UnityEditor.Animations.AnimatorStateMachine sm = animatorcontroller.layers[0].stateMachine;

                string name = sm.states[0].state.name;
                if (control != null)
                {
                    if (control.animationClips.Length == 1)
                    {
                        AnimationClip clip = control.animationClips[0];
                        Record(clip, name);
                    }
                }
            }

            if (obj.playbackTime == -1)
            {
                obj.enabled = true;

                RuntimeAnimatorController control = obj.runtimeAnimatorController;
                AnimatorStateMachine sm = animatorcontroller.layers[0].stateMachine;

                string name = sm.states[0].state.name;
                if (control != null)
                {
                    if (control.animationClips.Length == 1)
                    {
                        AnimationClip clip = control.animationClips[0];
                        Record(clip, name);
                    }
                }
            }

            obj.playbackTime = time;
            obj.Update(0);
        }
    }

    public class AnimationClipObjectTimeControl : TimeLineObjectBase<Animator>
    {
        public class NeedRecordAnimationClipInfo
        {
            public string stateName;
            public int frame;
        }

        public NeedRecordAnimationClipInfo record = new NeedRecordAnimationClipInfo();
        public bool isNeedRecord = true;
        public int state = 0;
        public int index = -1;

        public override void SetObject(Animator t, Action<float> action)
        {
            base.SetObject(t, action);
        }

        public void SetStateName(string stateName)
        {
            record.stateName = stateName;
            AnimatorController animatorcontroller = obj.runtimeAnimatorController as AnimatorController;
            AnimatorStateMachine sm = animatorcontroller.layers[0].stateMachine;

            if (stateName.Contains("skill"))
            {
                state = (int)AnimatorStateEnum.AnimatorSKILL;
                string[] namess = stateName.Split('_');

                int skilltype = int.Parse(namess[namess.Length - 2]);
                int skillIndex = int.Parse(namess[namess.Length - 1]);
                index = skilltype * 10 + skillIndex;
            }
            else
            {
                AnimatorStateEnum e = (AnimatorStateEnum)Enum.Parse(typeof(AnimatorStateEnum), "Animator_" + stateName.ToUpper());
                state = (int)e;
                index = -1;
            }

            foreach (UnityEditor.Animations.ChildAnimatorState state in sm.states)
            {
                if (state.state.name == record.stateName)
                {
                    AnimationClip clip = state.state.motion as AnimationClip;
                    int frame = (int)(clip.length * clip.frameRate);
                    record.frame = frame;
                }
            }

            Recond();
            TimeLength = obj.recorderStopTime;
        }

        public void Recond()
        {
            obj.StopPlayback();
            float frameTime = 1.0f / 30;
            obj.StartRecording(record.frame);
            obj.recorderStartTime = 0f;

            obj.Play(record.stateName);
            obj.SetInteger("state", state);

            if (index != -1)
            {
                obj.SetInteger("skilltype", index);
            }

            for (var j = 0; j <= record.frame; j++)
            {
                obj.Update(frameTime);
            }

            obj.StopRecording();
            obj.StartPlayback();
        }

        public override string GetName()
        {
            return "";
        }

        public override void TimeChange(float time)
        {
            if (isNeedRecord)
            {
                Recond();
                isNeedRecord = false;
            }

            //time = time / TimeLength;
            obj.playbackTime = time;
            obj.Update(time);
        }

        public override void LeaveTime(float time)
        {
            isNeedRecord = true;
        }
    }
}